﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using TookKit.Mvvm.Attributes;
using TookKit.Mvvm.Enums;
using TookKit.Mvvm.Extensions;
using TookKit.Mvvm.Interfaces;

namespace TookKit.Mvvm
{
    public class Container : IContainer
    {
        public static Container Default { get; } = new Lazy<Container>().Value;

        private readonly ConcurrentDictionary<Type, Type> _intferfaceMaps = new ConcurrentDictionary<Type, Type>();//接口与子类的映射字典
        private readonly ConcurrentDictionary<Type, ConstructorInfo> _constructors = new ConcurrentDictionary<Type, ConstructorInfo>();//接口与构造器的映射字典
        private readonly ConcurrentDictionary<Type, Dictionary<string, object>> _instancesRegistry = new ConcurrentDictionary<Type, Dictionary<string, object>>(); //已构造的实例注册集合
        private readonly ConcurrentDictionary<Type, Dictionary<string, Delegate>> _factories = new ConcurrentDictionary<Type, Dictionary<string, Delegate>>();//委托工厂集合
        private readonly string _defaultKey = Guid.NewGuid().ToString();
        public IModuleManager ModuleManager { get; } = new ModuleManager();

        

        public void Register<TInterface, TImplementation>()
            where TInterface : class
            where TImplementation : class
        {
            Type interfaceType = typeof(TInterface);
            Type serviceType = typeof(TImplementation);
            if (!_intferfaceMaps.ContainsKey(interfaceType))
            {
                _intferfaceMaps.TryAdd(interfaceType, serviceType);
                _constructors.TryAdd(serviceType, serviceType.GetConstructorInfo(_intferfaceMaps)); //添加当前Type的构造器
            }

            //todo 执行真正的注册代码

            Func<TInterface> factory = Resolve<TInterface>;
            DoRegister(interfaceType, factory, _defaultKey);
            
        }

        public void Register<TImplementation>() where TImplementation : class
        {
            Type serviceType = typeof(TImplementation);
            Register(serviceType);
        }

        /// <summary>
        /// 创建实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private T Resolve<T>()
        {
            var interfaceType = typeof(T);
            var constructor = _constructors.ContainsKey(interfaceType)
                ? _constructors[interfaceType]
                : interfaceType.GetConstructorInfo(_intferfaceMaps);
            var parameterInfos = constructor.GetParameters();
            if (parameterInfos.Length == 0)
            {
                return(T)constructor.Invoke(new object[0]);
            }

            var parameters = new object[parameterInfos.Length];
            foreach ( var param in parameterInfos)
            {
                parameters[param.Position] = GetService(param.ParameterType);//获取参数对象
            }
            return(T)constructor.Invoke(parameters);
        }
        public T GetService<T>()
        {
            return (T)GetService(typeof(T));
        }
        public object GetService(Type type) 
        {
            return DoGetService(type, _defaultKey);
        }

        private object DoGetService(Type interfaceType, string key)
        {
            key = string.IsNullOrEmpty(key) ? _defaultKey: key;
            Dictionary<string, object> instances = null;
            if (!_instancesRegistry.ContainsKey(interfaceType))
            {
                instances = new Dictionary<string, object>();
            }
            else
            {
                instances = _instancesRegistry[interfaceType];
            }

            if (instances != null && instances.ContainsKey(key))
            {
                return instances[key];
            }

            object instance = null;
            if (_factories.ContainsKey(interfaceType) && _factories[interfaceType].ContainsKey(key))
            {
                var t = _factories[interfaceType][key];
                var p = t.Method.GetParameters();
                if (p.Length ==1) 
                {
                    instance = _factories[interfaceType][key].DynamicInvoke(interfaceType);
                }
                else
                {
                    instance = _factories[interfaceType][key].DynamicInvoke(null);
                }
            }
            else if (_factories[interfaceType].ContainsKey(_defaultKey))
            {
                var t = _factories[interfaceType][key];
                var p = t.Method.GetParameters();
                if (p.Length == 1)
                {
                    instance = _factories[interfaceType][key].DynamicInvoke(interfaceType);
                }
                else
                {
                    instance = _factories[interfaceType][key].DynamicInvoke(null);
                }
            }

            if (instances != null)
            {
                var lifetime = GetLifetime(instance.GetType());
                if (lifetime == null || lifetime == Lifetime.Singleton)
                {
                    if (!_instancesRegistry.ContainsKey(interfaceType))
                    {
                        instances.Add(key, instance);
                        _instancesRegistry.TryAdd(interfaceType, instances);
                    }
                }

            }

            //DataContext自动绑定view与viewmodel
            var viewAttribute = GetViewAttribute(instance);
            if (viewAttribute != null)
            {
                AutoBindViewModel(instance);
            }
            return instance;
        }

        private void DoRegister<T>(Type interfaceType,Func<T> factory,string key)
        {
            if (_factories.ContainsKey(interfaceType))
            {
                if (_factories[interfaceType].ContainsKey(key))
                    return;
                _factories[interfaceType].Add(key, factory);
            }
            else
            {
                var list = new Dictionary<string, Delegate>();
                list.TryAdd(key, factory);
                _factories.TryAdd(interfaceType, list);
            }
        }

        public Lifetime? GetLifetime(Type type)
        {
            var attribute = type.GetCustomAttribute<DependencyInjectionAttribute>();
            if (attribute != null)
            {
                return attribute.Lifetime;
            }
            return null;
        }

        public void Register(List<Type> types)
        {
            if (types == null) return;

            foreach (Type serviceType in types)
            {
                var attributes = serviceType.GetDependencyInjectionAttributes();

                foreach (var attribute in attributes)
                {
                    if (attribute.InterfaceTypes.Length == 0)
                    {
                        Register(serviceType);//以类型的Type为Key值注册类型到字典中
                    }
                    else
                    {
                        foreach (var interfaceType in attribute.InterfaceTypes)
                        {
                            Register(interfaceType, serviceType);//以接口的Type为Key值注册类型到字典中
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 以类型的Type为Key值注册类型到字典中
        /// </summary>
        /// <param name="type"></param>
        public void Register(Type type)
        {
            if(!_intferfaceMaps.ContainsKey(type))
            {
                _intferfaceMaps.TryAdd(type, type);
                _constructors.TryAdd(type, type.GetConstructorInfo(_intferfaceMaps)); //添加当前Type的构造器
            }

            Func<Type, object> factory = Resolve;//第一种,有名方法

            factory = delegate //第二种，匿名方法
            {
                var constructor = _constructors.ContainsKey(type) ? _constructors[type] : type.GetConstructorInfo(_intferfaceMaps);
                var parameterInfos = constructor.GetParameters();
                if (parameterInfos.Length == 0)
                {
                    return constructor.Invoke(new object[0]);//以构造器创建实例（无参）
                }

                var parameters = new object[parameterInfos.Length];
                foreach (var item in parameterInfos)
                {
                    parameters[item.Position] = GetService(item.ParameterType);
                }

                return constructor.Invoke(parameters);//以构造器创建实例（有参）
            };


            if (_factories.ContainsKey(type))
            {
                if (_factories[type].ContainsKey(_defaultKey))
                    return;
                _factories[type].TryAdd(_defaultKey, factory);
            }
            else
            {
                var list =new Dictionary<string,Delegate>();
                list.TryAdd(_defaultKey, factory);
                _factories.TryAdd(type, list);
            }
        }

        /// <summary>
        /// 以Type创建实例
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private object Resolve(Type type)
        {
            var constructor = _constructors.ContainsKey(type) ? _constructors[type] : type.GetConstructorInfo(_intferfaceMaps);
            var parameterInfos = constructor.GetParameters();
            if (parameterInfos.Length == 0)
            {
                return constructor.Invoke(new object[0]);//以构造器创建实例（无参）
            }

            var parameters = new object[parameterInfos.Length];
            foreach (var item in parameterInfos)
            {
                parameters[item.Position] = GetService(item.ParameterType);
            }

            return constructor.Invoke(parameters);//以构造器创建实例（有参）
        }

        /// <summary>
        /// 以接口的Type为Key值注册类型到字典中
        /// </summary>
        /// <param name="interfaceType"></param>
        /// <param name="serviceType"></param>
        public void Register(Type interfaceType,Type serviceType)
        {
            if (!_intferfaceMaps.ContainsKey(interfaceType))
            {
                _intferfaceMaps.TryAdd(interfaceType,serviceType);
                _constructors.TryAdd(serviceType, serviceType.GetConstructorInfo(_intferfaceMaps));
            }

            Func<Type, object> factory = Resolve;//第一种,有名方法

            if (_factories.ContainsKey(interfaceType))
            {
                if (_factories[interfaceType].ContainsKey(_defaultKey))
                {
                    return;
                }
                _factories[interfaceType].TryAdd(_defaultKey,factory);
            }
            else
            {
                var list = new Dictionary<string, Delegate>();
                list.TryAdd(_defaultKey,factory);
                _factories.TryAdd(interfaceType, list);
            }
        }

        /// <summary>
        /// 获取View的ViewAttribute
        /// </summary>
        /// <param name="view"></param>
        /// <returns></returns>
        private ViewAttribute GetViewAttribute(object view)
        {
            var type = view.GetType();
            return type.GetCustomAttribute<ViewAttribute>();
        }

        /// <summary>
        /// view与viewmodel自动绑定
        /// </summary>
        /// <param name="view"></param>
        public void AutoBindViewModel(object view)
        {
            if(view is FrameworkElement element)
            {
                var viewType = view.GetType();
                var viewName = viewType.FullName;
                viewName = viewName.Replace(".Views.", ".ViewModels.");
                var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
                var suffix = viewName.EndsWith("View") ? "Model" : "ViewModel";
                var viewModelName = string.Format(CultureInfo.InvariantCulture, "{0}{1},{2}", viewName, suffix, viewAssemblyName);
                var viewModelType = Type.GetType(viewModelName);
                var viewModel = GetService(viewModelType);
                element.DataContext = viewModel;
            }             
        }
    }
}
